import copy
import math
from panda3d.core import *

'''
	finds the length of the speicfied vector
'''
def length(vector):
	return math.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2])

'''
	Andrew Oberlin
	Date Created: February 27, 2012
	Date Last Modified: February 27, 2012
'''
class CameraController:
	CAMERA_SPEED = 7.5
	CAMERA_ACCELERATION = 3.0
	'''
		Constructor for the Camera Controller class
		Declares the camera's position and angle at the
		start of the game
	'''
	def __init__(self, parent):
		self.parent = parent
		self.camera = self.parent.camera
		'''
		props = self.parent.base.win.getProperties()
		tmp = copy.deepcopy(props)
		tmp.setSize(self.parent.WIN_WIDTH, self.parent.WIN_HEIGHT)
		self.parent.base.win.requestProperties(tmp)
		'''
		
		self.free = False
		self.loadModels()
	
	'''
		Loads the different arrows to indicate camera movement
	'''
	def loadModels(self):
		self.models = list()
		texture = self.parent.loader.loadTexture("models/gui/game_maker/arrow.png")
		for i in range(2):
			model = self.parent.loader.loadModelCopy("models/plane")
			model.setTexture(texture)
			model.setR(i*180)
			model.setTransparency(1)
			model.setScale(Vec3(0.05,1,0.1))
			model.reparentTo(self.parent.base.aspect2d)
			model.hide()
			self.models.append(model)
			
		self.models[0].setPos(1.2,0,0.3) # right arrow
		self.models[1].setPos(-1.2,0,0.3) # left arrow
	
	'''
		Starts the task that moves the camera
	'''
	def startMouseWatch(self):
		self.prevTime = 0
		self.velocity = self.CAMERA_SPEED
		self.parent.taskMgr.add(self.cameraMoveTask, 'mouse_map_move')
		
	'''
		Ends the task that moves the camera
	'''
	def endMouseWatch(self):
		self.parent.taskMgr.remove('mouse_map_move')
		
		
	'''
		Moves the camera when the mouse is on one of the edges of the screen
	'''
	def cameraMoveTask(self, task):
		deltaT = task.time - self.prevTime
		self.prevTime = task.time
		self.velocity = self.velocity + deltaT*self.CAMERA_ACCELERATION
		if (self.parent.base.mouseWatcherNode.hasMouse()):
			mouseX = self.parent.base.mouseWatcherNode.getMouseX()
			mouseY = self.parent.base.mouseWatcherNode.getMouseY()
			
			if (mouseY > -0.5 and mouseY < 0.9):
				if (mouseX > 0.9 or mouseX < -0.9):
					if (mouseX > 0.9):
						if (self.models[0].isHidden()):
							self.models[0].show()
						self.camera.setX(self.camera.getX() + deltaT*self.velocity)
					elif (mouseX < -0.9):
						if (self.models[1].isHidden()):
							self.models[1].show()
						self.camera.setX(self.camera.getX() - deltaT*self.velocity)
					else:
						self.models[0].hide()
						self.models[1].hide()
						
				else:
					self.velocity = self.CAMERA_SPEED
					self.models[0].hide()
					self.models[1].hide()
			
		
		return task.cont
		
	'''
		Moves the camera so that it is looking at the position indicated
	'''
	def moveTo(self, x=None, y=None, z=None):
		if (x != None):
			self.camera.setX(x)
		if (y != None):
			self.camera.sety(y)
		if (z != None):
			self.camera.setZ(z)
		
	'''
		Makes its so that the camera can move using the 
		arrow keys and wasd
	'''
	def makeFree(self):
		if (self.free == False):
			self.parent.accept("w", self.move_camera, [-1])
			self.parent.accept("s", self.move_camera, [1])
			self.parent.accept("a", self.strafe_camera, [-1])
			self.parent.accept("d", self.strafe_camera, [1])
			self.parent.accept("arrow_left", self.rotate_camera, [1])
			self.parent.accept("arrow_right", self.rotate_camera, [-1])
			self.parent.accept("arrow_up", self.rotate_camera_pitch, [1])
			self.parent.accept("arrow_down", self.rotate_camera_pitch, [-1])
			self.parent.accept("p", self.print_camera_pos)
			
		self.free = True
		
	'''
		Translates the camera to a new position
	
		Params: direction -- the direction of movement, -1 for forward and 1 for backward
	'''
	def move_camera(self, direction):
		dist = 3
		angle = self.camera.getH()*math.pi/180.0
		dx = dist*direction*math.sin(angle)
		dy = -1*dist*direction*math.cos(angle)
		old_pos = self.camera.getPos()
		self.camera.setPos(old_pos + Vec3(dx, dy, 0))
		'''
		if (self.camera.getX() >= 250 or self.camera.getX() < -250):
			self.camera.setPos(old_pos)
		'''
	'''
		Translates the camera to a new position
	
		Params: direction -- the direction of movement, -1 for left and 1 for right
	'''
	def strafe_camera(self, direction):
		dist = 3
		angle = self.camera.getH()*math.pi/180.0
		dy = dist*direction*math.sin(angle)
		dx = 1*dist*direction*math.cos(angle)
		old_pos = self.camera.getPos()
		self.camera.setPos(old_pos + Vec3(dx, dy, 0))
		'''
		if (length(self.camera.getPos()) >= 50 or self.camera.getZ() < 0):
			self.camera.setPos(old_pos)
		'''
	
	'''
		Rotates the camera's heading
		
		Params: direction -- direction of the rotation, 1 being left and -1 being right
	'''
	def rotate_camera(self, direction):
		self.camera.setH(self.camera.getH() + direction*5)
		
	'''
		Makes the camera move in its pitch
	
		Params: direction -- direction of the rotation up or down
	'''
	def rotate_camera_pitch(self, direction):
		self.camera.setP(self.camera.getP() + direction*5);
	
	'''
		Prints the camera's position
	'''
	def print_camera_pos(self):
		print "Camera position: " + str(self.camera.getPos())
		print "Camera hpr: " + str(self.camera.getHpr())
		
	
		
		
		

		
